001 /**
002 * Copyright 2003-2004 The Apache Software Foundation
003 * Copyright 2005 Stephen McConnell
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package net.dpml.cli.util;
018
019 import java.util.Comparator;
020 import java.util.List;
021
022 import net.dpml.cli.Group;
023 import net.dpml.cli.Option;
024 import net.dpml.cli.option.Command;
025 import net.dpml.cli.option.DefaultOption;
026 import net.dpml.cli.option.Switch;
027
028 /**
029 * A collection of Comparators suitable for use with Option instances.
030 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
031 * @version 1.0.0
032 */
033 public final class Comparators
034 {
035 private Comparators()
036 {
037 // static
038 }
039
040 /**
041 * Chains comparators together.
042 *
043 * @see #chain(Comparator[])
044 * @param c0 a comparator
045 * @param c1 a comparator
046 * @return a chained comparator
047 */
048 public static Comparator chain( final Comparator c0, final Comparator c1 )
049 {
050 return chain( new Comparator[]{c0, c1} );
051 }
052
053 /**
054 * Chains comparators together.
055 *
056 * @see #chain(Comparator[])
057 * @param c0 a comparator
058 * @param c1 a comparator
059 * @param c2 a comparator
060 * @return a chained comparator
061 */
062 public static Comparator chain( final Comparator c0, final Comparator c1, final Comparator c2 )
063 {
064 return chain( new Comparator[]{c0, c1, c2} );
065 }
066
067 /**
068 * Chains comparators together.
069 *
070 * @see #chain(Comparator[])
071 * @param c0 a comparator
072 * @param c1 a comparator
073 * @param c2 a comparator
074 * @param c3 a comparator
075 * @return a chained comparator
076 */
077 public static Comparator chain(
078 final Comparator c0, final Comparator c1, final Comparator c2, final Comparator c3 )
079 {
080 return chain( new Comparator[]{c0, c1, c2, c3} );
081 }
082
083 /**
084 * Chains comparators together.
085 *
086 * @see #chain(Comparator[])
087 * @param c0 a comparator
088 * @param c1 a comparator
089 * @param c2 a comparator
090 * @param c3 a comparator
091 * @param c4 a comparator
092 * @return a chained comparator
093 */
094 public static Comparator chain(
095 final Comparator c0, final Comparator c1, final Comparator c2,
096 final Comparator c3, final Comparator c4 )
097 {
098 return chain( new Comparator[]{c0, c1, c2, c3, c4} );
099 }
100
101 /**
102 * Chains comparators together.
103 *
104 * @see #chain(Comparator[])
105 * @param comparators a List of comparators to chain together
106 * @return a chained comparator
107 */
108 public static Comparator chain( final List comparators )
109 {
110 return new Chain(
111 (Comparator[]) comparators.toArray(
112 new Comparator[ comparators.size() ] ) );
113 }
114
115 /**
116 * Chains an array of comparators together. Each Comparator will be called
117 * in turn until one of them return a non-zero value, this value will be
118 * returned.
119 *
120 * @param comparators the array of comparators
121 * @return a chained comparator
122 */
123 public static Comparator chain( final Comparator[] comparators )
124 {
125 return new Chain( comparators );
126 }
127
128 /**
129 * Chains a series of Comparators together.
130 */
131 private static class Chain implements Comparator
132 {
133 private final Comparator[] m_chain;
134
135 /**
136 * Creates a Comparator chain using the specified array of Comparators
137 * @param chain the Comparators in the chain
138 */
139 public Chain( final Comparator[] chain )
140 {
141 m_chain = new Comparator[ chain.length ];
142 System.arraycopy( chain, 0, m_chain, 0, chain.length );
143 }
144
145 /**
146 * Compare two values.
147 * @param left the first value
148 * @param right the second value
149 * @return the result
150 */
151 public int compare( final Object left, final Object right )
152 {
153 int result = 0;
154 for( int i = 0; result == 0 && i < m_chain.length; ++i )
155 {
156 result = m_chain[i].compare( left, right );
157 }
158 return result;
159 }
160 }
161
162 /**
163 * Reverses a comparator's logic.
164 *
165 * @param wrapped
166 * the Comparator to reverse the logic of
167 * @return a comparator with reverse logic
168 */
169 private static Comparator reverse( final Comparator wrapped )
170 {
171 return new Reverse( wrapped );
172 }
173
174 /**
175 * A reverse comparator.
176 */
177 private static class Reverse implements Comparator
178 {
179 private final Comparator m_wrapped;
180
181 /**
182 * Creates a Comparator with reverse logic
183 * @param wrapped the original logic
184 */
185 public Reverse( final Comparator wrapped )
186 {
187 m_wrapped = wrapped;
188 }
189
190 /**
191 * Compare two values.
192 * @param left the first value
193 * @param right the second value
194 * @return the result
195 */
196 public int compare( final Object left, final Object right )
197 {
198 return -m_wrapped.compare( left, right );
199 }
200 }
201
202 /**
203 * Forces Group instances to appear at the beginning of lists
204 *
205 * @see Group
206 * @return a new comparator
207 */
208 public static Comparator groupFirst()
209 {
210 return new GroupFirst();
211 }
212
213 /**
214 * Forces Group instances to appear at the end of lists
215 *
216 * @see Group
217 * @return a new comparator
218 */
219 public static Comparator groupLast()
220 {
221 return reverse( groupFirst() );
222 }
223
224 /**
225 * A group first comparator.
226 */
227 private static class GroupFirst implements Comparator
228 {
229 /**
230 * Compare two values.
231 * @param left the first value
232 * @param right the second value
233 * @return the result
234 */
235 public int compare( final Object left, final Object right )
236 {
237 final boolean l = left instanceof Group;
238 final boolean r = right instanceof Group;
239
240 if( l ^ r )
241 {
242 if( l )
243 {
244 return -1;
245 }
246 return 1;
247 }
248 return 0;
249 }
250 }
251
252 /**
253 * Forces Switch instances to appear at the beginning of lists
254 *
255 * @see Switch
256 * @return a new comparator
257 */
258 public static Comparator switchFirst()
259 {
260 return new SwitchFirst();
261 }
262
263 /**
264 * Forces Switch instances to appear at the end of lists
265 *
266 * @see Switch
267 * @return a new comparator
268 */
269 public static Comparator switchLast()
270 {
271 return reverse( switchFirst() );
272 }
273
274 /**
275 * A switch first comparator.
276 */
277 private static class SwitchFirst implements Comparator
278 {
279 /**
280 * Compare two values.
281 * @param left the first value
282 * @param right the second value
283 * @return the result
284 */
285 public int compare( final Object left, final Object right )
286 {
287 final boolean l = left instanceof Switch;
288 final boolean r = right instanceof Switch;
289
290 if( l ^ r )
291 {
292 if( l )
293 {
294 return -1;
295 }
296 return 1;
297 }
298 return 0;
299 }
300 }
301
302 /**
303 * Forces Command instances to appear at the beginning of lists
304 *
305 * @see Command
306 * @return a new comparator
307 */
308 public static Comparator commandFirst()
309 {
310 return new CommandFirst();
311 }
312
313 /**
314 * Forces Command instances to appear at the end of lists
315 *
316 * @see Command
317 * @return a new comparator
318 */
319 public static Comparator commandLast()
320 {
321 return reverse( commandFirst() );
322 }
323
324 /**
325 * A command first comparator.
326 */
327 private static class CommandFirst implements Comparator
328 {
329 /**
330 * Compare two values.
331 * @param left the first value
332 * @param right the second value
333 * @return the result
334 */
335 public int compare( final Object left, final Object right )
336 {
337 final boolean l = left instanceof Command;
338 final boolean r = right instanceof Command;
339
340 if( l ^ r )
341 {
342 if( l )
343 {
344 return -1;
345 }
346 return 1;
347 }
348 return 0;
349 }
350 }
351
352 /**
353 * Forces DefaultOption instances to appear at the beginning of lists
354 *
355 * @see DefaultOption
356 * @return a new comparator
357 */
358 public static Comparator defaultOptionFirst()
359 {
360 return new DefaultOptionFirst();
361 }
362
363 /**
364 * Forces DefaultOption instances to appear at the end of lists
365 *
366 * @see DefaultOption
367 * @return a new comparator
368 */
369 public static Comparator defaultOptionLast()
370 {
371 return reverse( defaultOptionFirst() );
372 }
373
374 /**
375 * An option first comparator.
376 */
377 private static class DefaultOptionFirst implements Comparator
378 {
379 /**
380 * Compare two values.
381 * @param left the first value
382 * @param right the second value
383 * @return the result
384 */
385 public int compare( final Object left, final Object right )
386 {
387 final boolean l = left instanceof DefaultOption;
388 final boolean r = right instanceof DefaultOption;
389
390 if( l ^ r )
391 {
392 if( l )
393 {
394 return -1;
395 }
396 return 1;
397 }
398 return 0;
399 }
400 }
401
402 /**
403 * Forces Comparators with a particular trigger to appear at the beginning
404 * of lists
405 *
406 * @param name
407 * the trigger name to select
408 * @see Option#getTriggers()
409 * @return a new comparator
410 */
411 public static Comparator namedFirst( final String name )
412 {
413 return new Named( name );
414 }
415
416 /**
417 * Forces Comparators with a particular trigger to appear at the end of
418 * lists
419 *
420 * @param name
421 * the trigger name to select
422 * @see Option#getTriggers()
423 * @return a new comparator
424 */
425 public static Comparator namedLast( final String name )
426 {
427 return reverse( new Named( name ) );
428 }
429
430 /**
431 * A named comparator.
432 */
433 private static class Named implements Comparator
434 {
435 private final String m_name;
436
437 /**
438 * Creates a Comparator that sorts a particular name high in order
439 * @param name the trigger name to select
440 */
441 public Named( final String name )
442 {
443 m_name = name;
444 }
445
446 /**
447 * Compare two values.
448 * @param primary the first value
449 * @param secondary the second value
450 * @return the result
451 */
452 public int compare( final Object primary, final Object secondary )
453 {
454 final Option left = (Option) primary;
455 final Option right = (Option) secondary;
456
457 final boolean l = left.getTriggers().contains( m_name );
458 final boolean r = right.getTriggers().contains( m_name );
459
460 if( l ^ r )
461 {
462 if( l )
463 {
464 return -1;
465 }
466 return 1;
467 }
468 return 0;
469 }
470 }
471
472 /**
473 * Orders Options by preferredName
474 *
475 * @see Option#getPreferredName()
476 * @return a new comparator
477 */
478 public static Comparator preferredNameFirst()
479 {
480 return new PreferredName();
481 }
482
483 /**
484 * Orders Options by preferredName, reversed
485 *
486 * @see Option#getPreferredName()
487 * @return a new comparator
488 */
489 public static Comparator preferredNameLast()
490 {
491 return reverse( preferredNameFirst() );
492 }
493
494 /**
495 * A preferred name comparator.
496 */
497 private static class PreferredName implements Comparator
498 {
499 /**
500 * Compare two values.
501 * @param primary the first value
502 * @param secondary the second value
503 * @return the result
504 */
505 public int compare( final Object primary, final Object secondary )
506 {
507 final Option left = (Option) primary;
508 final Option right = (Option) secondary;
509 return left.getPreferredName().compareTo( right.getPreferredName() );
510 }
511 }
512
513 /**
514 * Orders Options grouping required Options first
515 *
516 * @see Option#isRequired()
517 * @return a new comparator
518 */
519 public static Comparator requiredFirst()
520 {
521 return new Required();
522 }
523
524 /**
525 * Orders Options grouping required Options last
526 *
527 * @see Option#isRequired()
528 * @return a new comparator
529 */
530 public static Comparator requiredLast()
531 {
532 return reverse( requiredFirst() );
533 }
534
535 /**
536 * A required comparator.
537 */
538 private static class Required implements Comparator
539 {
540 /**
541 * Compare two values.
542 * @param primary the first value
543 * @param secondary the second value
544 * @return the result
545 */
546 public int compare( final Object primary, final Object secondary )
547 {
548 final Option left = (Option) primary;
549 final Option right = (Option) secondary;
550
551 final boolean l = left.isRequired();
552 final boolean r = right.isRequired();
553
554 if( l ^ r )
555 {
556 if( l )
557 {
558 return -1;
559 }
560 return 1;
561 }
562 return 0;
563 }
564 }
565 }